package qq2564874169.tuaotuao.fx.orm.where;


import qq2564874169.tuaotuao.fx.Action1T;
import qq2564874169.tuaotuao.fx.Action2T;
import qq2564874169.tuaotuao.fx.FxAssert;
import qq2564874169.tuaotuao.fx.FxStream;
import qq2564874169.tuaotuao.fx.orm.DbEntity;
import qq2564874169.tuaotuao.fx.orm.query.ForUpdate;
import qq2564874169.tuaotuao.fx.utils.ClassUtil;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class SetWhere<T> {
    private Class<T> table;
    private Boolean allowEmptyCondition;
    private String splitCondition;
    private String fields;
    private T eq;
    private T neq;
    private T less;
    private T greater;
    private T greaterEq;
    private T lessEq;
    private T like;
    private T notLike;
    private T isNull;
    private T isNotNull;
    private List<T> in;
    private List<T> inOrNull;
    private List<T> notIn;
    private List<T> notInOrNull;
    private Integer skip;
    private Integer take;
    private T desc;
    private T asc;
    private String index;
    private ForUpdate forUpdate;

    public SetWhere(Class<T> table) {
        this.table = table;
    }

    public QueryWhere<T> queryWhere() {
        return new QueryWhere<T>(table) {

            @Override
            public ForUpdate forUpdate() {
                return forUpdate == null ? super.forUpdate() : forUpdate;
            }

            @Override
            public boolean allowEmptyCondition() {
                return allowEmptyCondition == null ? super.allowEmptyCondition() : allowEmptyCondition;
            }

            @Override
            public Integer skip() {
                return skip == null ? super.skip() : skip;
            }

            @Override
            public Integer take() {
                return take == null ? super.take() : take;
            }

            @Override
            public List<T> in() {
                return in == null ? super.in() : in;
            }

            @Override
            public List<T> inOrNull() {
                return inOrNull == null ? super.inOrNull() : inOrNull;
            }

            @Override
            public String fields() {
                return fields == null ? super.fields() : fields;
            }

            @Override
            public String splitCondition() {
                return splitCondition == null ? super.splitCondition() : splitCondition;
            }

            @Override
            public T eq() {
                return eq == null ? super.eq() : eq;
            }

            @Override
            public T asc() {
                return asc == null ? super.asc() : asc;
            }

            @Override
            public T desc() {
                return desc == null ? super.desc() : desc;
            }

            @Override
            public T greater() {
                return greater == null ? super.greater() : greater;
            }

            @Override
            public T greaterEq() {
                return greaterEq == null ? super.greaterEq() : greaterEq;
            }

            @Override
            public T isNotNull() {
                return isNotNull == null ? super.isNotNull() : isNotNull;
            }

            @Override
            public T isNull() {
                return isNull == null ? super.isNull() : isNull;
            }

            @Override
            public T less() {
                return less == null ? super.less() : less;
            }

            @Override
            public T lessEq() {
                return lessEq == null ? super.lessEq() : lessEq;
            }

            @Override
            public T like() {
                return like == null ? super.like() : like;
            }

            @Override
            public T notLike() {
                return notLike == null ? super.notLike() : notLike;
            }

            @Override
            public T neq() {
                return neq == null ? super.neq() : neq;
            }

            @Override
            public String index() {
                return index == null ? super.index() : index;
            }

            @Override
            public List<T> notIn() {
                return notIn == null ? super.notIn() : notIn;
            }

            @Override
            public List<T> notInOrNull() {
                return notInOrNull == null ? super.notInOrNull() : notInOrNull;
            }
        };
    }

    public ExecuteWhere<T> executeWhere() {
        FxAssert.isNull(fields, new RuntimeException("ExecuteWhere不能设置fields"));
        FxAssert.isNull(skip, new RuntimeException("ExecuteWhere不能设置skip"));
        FxAssert.isNull(asc, new RuntimeException("ExecuteWhere不能设置asc"));
        FxAssert.isNull(desc, new RuntimeException("ExecuteWhere不能设置desc"));
        FxAssert.isNull(forUpdate, new RuntimeException("ExecuteWhere不能设置forUpdate"));

        return new ExecuteWhere<T>(table) {
            @Override
            public boolean allowEmptyCondition() {
                return allowEmptyCondition == null ? super.allowEmptyCondition() : allowEmptyCondition;
            }

            @Override
            public List<T> in() {
                return in == null ? super.in() : in;
            }

            @Override
            public List<T> inOrNull() {
                return inOrNull == null ? super.inOrNull() : inOrNull;
            }

            @Override
            public String splitCondition() {
                return splitCondition == null ? super.splitCondition() : splitCondition;
            }

            @Override
            public T eq() {
                return eq == null ? super.eq() : eq;
            }

            @Override
            public T greater() {
                return greater == null ? super.greater() : greater;
            }

            @Override
            public T greaterEq() {
                return greaterEq == null ? super.greaterEq() : greaterEq;
            }

            @Override
            public T isNotNull() {
                return isNotNull == null ? super.isNotNull() : isNotNull;
            }

            @Override
            public T isNull() {
                return isNull == null ? super.isNull() : isNull;
            }

            @Override
            public T less() {
                return less == null ? super.less() : less;
            }

            @Override
            public T lessEq() {
                return lessEq == null ? super.lessEq() : lessEq;
            }

            @Override
            public T like() {
                return like == null ? super.like() : like;
            }

            @Override
            public T notLike() {
                return notLike == null ? super.notLike() : notLike;
            }

            @Override
            public T neq() {
                return neq == null ? super.neq() : neq;
            }

            @Override
            public String index() {
                return index == null ? super.index() : index;
            }

            @Override
            public List<T> notIn() {
                return notIn == null ? super.notIn() : notIn;
            }

            @Override
            public List<T> notInOrNull() {
                return notInOrNull == null ? super.notInOrNull() : notInOrNull;
            }
        };
    }

    public SetWhere<T> forUpdate(ForUpdate e) {
        this.forUpdate = e;
        return this;
    }

    public SetWhere<T> allowEmptyCondition(Boolean b) {
        allowEmptyCondition = b;
        return this;
    }

    public SetWhere<T> splitCondition(String s) {
        splitCondition = s;
        return this;
    }

    public SetWhere<T> fields(Action1T<T> action) {
        T model = ClassUtil.setNew(table);
        action.execute(model);
        DbEntity entity = DbEntity.get(table);
        Map<String, Object> values = entity.getValues(model);
        if (values.isEmpty() == false) {
            fields = FxStream.create(values.keySet()).strjoin(",");
        }
        return this;
    }

    public SetWhere<T> eq(Action1T<T> action) {
        eq = ClassUtil.setNew(table);
        action.execute(eq);
        return this;
    }

    public SetWhere<T> neq(Action1T<T> action) {
        neq = ClassUtil.setNew(table);
        action.execute(neq);
        return this;
    }

    public SetWhere<T> less(Action1T<T> action) {
        less = ClassUtil.setNew(table);
        action.execute(less);
        return this;
    }

    public SetWhere<T> greater(Action1T<T> action) {
        greater = ClassUtil.setNew(table);
        action.execute(greater);
        return this;
    }

    public SetWhere<T> lessEq(Action1T<T> action) {
        lessEq = ClassUtil.setNew(table);
        action.execute(lessEq);
        return this;
    }

    public SetWhere<T> greaterEq(Action1T<T> action) {
        greaterEq = ClassUtil.setNew(table);
        action.execute(greaterEq);
        return this;
    }

    public SetWhere<T> like(Action1T<T> action) {
        like = ClassUtil.setNew(table);
        action.execute(like);
        return this;
    }

    public SetWhere<T> notLike(Action1T<T> action) {
        notLike = ClassUtil.setNew(table);
        action.execute(notLike);
        return this;
    }

    public SetWhere<T> isNull(Action1T<T> action) {
        isNull = ClassUtil.setNew(table);
        action.execute(isNull);
        return this;
    }

    public SetWhere<T> isNotNull(Action1T<T> action) {
        isNotNull = ClassUtil.setNew(table);
        action.execute(isNotNull);
        return this;
    }

    public <V> List<T> in(List<V> items, Action2T<T, V> action) {
        if (in == null) {
            in = new ArrayList<>();
        }
        if (!items.isEmpty()) {
            List<T> list = new ArrayList<>(items.size());
            for (V item : items) {
                T model = ClassUtil.setNew(table);
                action.execute(model, item);
                list.add(model);
            }
            in.addAll(list);
        }
        return in;
    }

    public <V> List<T> inOrNull(List<V> items, Action2T<T, V> action) {
        if (inOrNull == null) {
            inOrNull = new ArrayList<>();
        }
        if (!items.isEmpty()) {
            List<T> list = new ArrayList<>(items.size());
            for (V item : items) {
                T model = ClassUtil.setNew(table);
                action.execute(model, item);
                list.add(model);
            }
            inOrNull.addAll(list);
        }
        return inOrNull;
    }

    public <V> List<T> notIn(List<V> items, Action2T<T, V> action) {
        if (notIn == null) {
            notIn = new ArrayList<>();
        }
        if (!items.isEmpty()) {
            List<T> list = new ArrayList<>(items.size());
            for (V item : items) {
                T model = ClassUtil.setNew(table);
                action.execute(model, item);
                list.add(model);
            }
            notIn.addAll(list);
        }
        return notIn;
    }

    public <V> List<T> notInOrNull(List<V> items, Action2T<T, V> action) {
        if (notInOrNull == null) {
            notInOrNull = new ArrayList<>();
        }
        if (!items.isEmpty()) {
            List<T> list = new ArrayList<>(items.size());
            for (V item : items) {
                T model = ClassUtil.setNew(table);
                action.execute(model, item);
                list.add(model);
            }
            notInOrNull.addAll(list);
        }
        return notInOrNull;
    }

    public SetWhere<T> skip(Integer i) {
        skip = i;
        return this;
    }

    public SetWhere<T> take(Integer i) {
        take = i;
        return this;
    }

    public SetWhere<T> asc(Action1T<T> action) {
        asc = ClassUtil.setNew(table);
        action.execute(asc);
        return this;
    }

    public SetWhere<T> desc(Action1T<T> action) {
        desc = ClassUtil.setNew(table);
        action.execute(desc);
        return this;
    }

    public SetWhere<T> index(String name) {
        this.index = name;
        return this;
    }
}
